<template>
  <div class="mod-category">
    <el-card class="box-card" style="min-width: 400px">
      <template #header>
        <div class="clearfix">
          <span class="c-title">分类结构</span>
        </div>
      </template>
      <el-row :gutter="20" class="toolbar-box">
        <el-col :span="14">
          <el-input placeholder="输入关键字进行过滤" v-model="filterTreeText" />
        </el-col>
        <el-col :span="10">
          <el-button-group class="toolbar-btngroup fr">
            <el-button v-if="admin.isAuth('product:category:save')" @click="() => addCategoryEvent('add-root')" type="primary">
              新增
            </el-button>
            <el-button v-if="admin.isAuth('product:category:save')" @click="() => updateCategoryEvent()" type="warning">
              修改
            </el-button>
            <el-button v-if="admin.isAuth('product:category:delete')" @click="() => deleteCategoryEvent()" type="danger">
              删除
            </el-button>
            <el-button v-if="admin.isAuth('product:category:published')" @click="() => publishedCategoryEvent()" type="danger">
              发布
            </el-button>
          </el-button-group>
        </el-col>
      </el-row>
      <div style="height: 100%">
        <el-tree
          node-key="id"
          class="filter-tree"
          highlight-current
          :props="tree.props"
          :data="tree.data"
          :expand-on-click-node="true"
          draggable
          :allow-drop="collapse"
          :default-expanded-keys="tree.expandedKeys"
          @node-expand="treeNodeExpandEvent"
          @node-collapse="treeNodeCollapseEvent"
          v-loading.lock="tree.loading"
          element-loading-text="拼命加载中"
          :filter-node-method="filterTreeNode"
          ref="treeRef"
        >
          <template #default="{ node, data }">
            <span class="custom-tree-node">
              <icon-svg v-if="data.attributes && data.attributes.icon" :name="data.attributes.icon"></icon-svg>
              <span>{{ node.label }}&nbsp;&nbsp;</span>
              <span class="fr">
                <el-button v-if="admin.isAuth('product:category:save') && data.attributes && data.attributes.level < 3" link size="small" @click.stop="() => addCategoryEvent('add-node', data)">
                  新增
                </el-button>
              </span>
            </span>
          </template>
        </el-tree>
      </div>
    </el-card>
    <!-- 弹窗, 新增 / 修改 -->
    <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdateRef" @initCategoryData="initCategoryData" />
  </div>
</template>

<script lang="ts" setup>
import admin from "@/utils/admin";
import http from "@/utils/httpRequest";
import { ref, reactive, watch, nextTick, onMounted } from "vue";
import { ElTree, ElMessage, ElMessageBox } from "element-plus";

import AddOrUpdate from "./category-add-or-update.vue";

// 分类树形结构
const tree = reactive({
  // 属性结构
  data: [],
  // 加载状态
  loading: false,
  // 当前选中的节点，即当前查看请求列表的菜单节点
  selectData: undefined,
  // 菜单树默认属性
  props: {
    label: "name",
    children: "children",
  },
  // 展开节点
  expandedKeys: [],
});

// 菜单树过滤文本
const filterTreeText = ref("");

// 新增修改弹窗是否显示
const addOrUpdateVisible = ref(false);

// 弹窗引用
const addOrUpdateRef = ref();

// 资源树引用
const treeRef = ref<InstanceType<typeof ElTree>>();

// 监听查询内容变化
watch(filterTreeText, (n, o) => {
  treeRef.value!.filter(n);
});

// 组件挂载完成后执行
onMounted(() => {
  initCategoryData();
});

// 加载分类结构数据
const initCategoryData = () => {
  tree.loading = true;
  http
    .post({
      url: "/product/category/mtree",
    })
    .then(({ data }) => {
      if (http.success(data)) {
        tree.data = data.body;
      }
      tree.loading = false;
    });
};

// 新增分类
const addCategoryEvent = async (action, data = null) => {
  addOrUpdateVisible.value = true;
  if (action === "add-node") {
    if (data && data.attributes && data.attributes.level >= 3) {
      ElMessage.error("商品分类最多允许3层结构，请确认后操作！");
      return;
    }
  }
  await nextTick();
  addOrUpdateRef.value.initForm(action, action === "add-root" ? tree.data : data);
};

// 修改分类
const updateCategoryEvent = async () => {
  let node = treeRef.value.getCurrentNode();
  if (!node) {
    ElMessage.error("请先选择要修改的分类数据！");
    return;
  }
  addOrUpdateVisible.value = true;
  await nextTick();
  addOrUpdateRef.value.initForm("update-node", node);
};

// 删除分类
const deleteCategoryEvent = () => {
  let node = treeRef.value.getCurrentNode();
  if (!node) {
    ElMessage.error("请先选择要删除的分类数据！");
    return;
  }
  ElMessageBox
    .confirm(`确定要删除[${node.name}]分类吗?`, "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    })
    .then(() => {
      http
        .instance({
          url: http.adornUrl("/product/category/delete"),
          method: "post",
          data: http.adornData([node.id], false),
        }).then(({ data }) => {
          if (http.success(data, true, true)) {
            initCategoryData();
          }
        });
    })
    .catch(()=>{});
};

// 拖拽时判定目标节点能否被放置
const collapse = (moveNode, inNode, type) => {
  // 只能创建3级分类，所以只需要判断插入节点级别不能为3级即可
  if (type === "inner") {
    let level = inNode.attributes && inNode.attributes.level;
    if (level === undefined) {
      ElMessage.error("未获取到插入节点的层次！");
      return false;
    }
    if (level >= 3) {
      ElMessage.error(`不能拖入[${inNode.name}]节点，商品分类最多允许3层结构！`);
      return false;
    }
  }
  return true;
};

// 菜单展开事件
const treeNodeExpandEvent = (data) => {
  if (tree.expandedKeys.indexOf(data.id) === -1) {
    tree.expandedKeys.push(data.id);
  }
};

// 菜单关闭事件
const treeNodeCollapseEvent = (data) => {
  let expandedKeys = tree.expandedKeys;
  for (let i = 0; i < expandedKeys.length; i++) {
    if (expandedKeys[i] === data.id) {
      expandedKeys.splice(i, 1);
    }
    let children = data.children;
    if (children && children.length > 0) {
      for (let h = 0; h < children.length; h++) {
        treeNodeCollapseEvent(children[h]);
      }
    }
  }
};

// 刷新最新的分类树
const publishedCategoryEvent = () => {
  ElMessageBox.confirm(`确定要发布最新的分类树吗?`, "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  }).then(() => {
    http
      .post({
        url: `/product/category/tree-refresh`,
      }).then(({ data }) => {
        http.success(data, true, true);
      });
  });
};

// 过滤菜单
const filterTreeNode = (value, data) => {
  if (!value) {
    return true;
  }
  return data.name.indexOf(value) !== -1;
};
</script>

<style lang="scss">
.mod-category {

  .c-title {
    font-size: 16px;
    font-weight: 600;
  }

  .toolbar-box {
    margin: 10px 0;
  }

  .el-tree-node__label {
    width: 100%;
  }
}
</style>